package bloodfang.gui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import bloodfang.StatBlock;

public class ItemDB {
	
	private static String wowheadPrefix = "wod";
	
	private HashSet<Item> itemDB = new HashSet<>();
	private HashSet<Gem> gemDB = new HashSet<>();

	public static Item get(int itemid, int upgrade_level, int random_suffix){
		if(itemid == 0)
			return null;
		Item i = getItemFromWOWHEAD(itemid);
		int ilvl = i.getItemLevel();
		ilvl = ilvl + upgrade_level * (i.getQuality() == 3 ? 8 : 4);
		i.setItemLevel(ilvl);
		return i;
	}
	
	public static Gem getGem(int itemid){
		if(itemid == 0)
			return null;
		Gem i = getGemFromWOWHEAD(itemid);
		return i;
	}
	
	private static Gem getGemFromWOWHEAD(int id){
		Gem gem = new Gem();
		
		JSONObject data = getItemDataWowHead(id);
		JSONObject extra;
		try {
			extra = data.getJSONObject("extra");

			//System.out.println(data.toString(1));
			
			gem.setName(data.getString("name"));
			gem.setIcon(data.getString("icon"));
			gem.setQuality(data.getInt("quality"));
			
			gem.add(new StatBlock(data));
			
			if(extra.has("id"))
				gem.setId(extra.getInt("id"));
			if(extra.has("subclass"))
				gem.setType(extra.getInt("subclass"));
			if(data.has("reqskill")){
				gem.setReqSkill(data.getInt("reqskill"));
			}
//			if(gearBuffDB.isCritMetaGem(id))
//				gem.setGearBuff("metagem_critdmg");
//			if(gearBuffDB.isCapacitivePrimalDiamond(id))
//				gem.setGearBuff("capacitive_primal_diamond");

		} catch (JSONException e) {
			e.printStackTrace();
		} catch (NullPointerException e) {
			//e.printStackTrace();
			return null;
		}
		
		return gem;
	}
	
	public ArrayList<Item> findAllWithInventorySlot(Slot slot){
		List<Integer> integers = slot.getInventorySlots();
		//Arrays.sort(integers);
		ArrayList<Item> list = new ArrayList<Item>();
		for(Item item : itemDB){
			int invSlot = item.getInventorySlot();
			if(!integers.contains(invSlot)) continue;
			list.add(item);
		}
		return list;
	}
	
	public Collection<Gem> findAllGemsWithMatchingColor(Slot slot) {
		
		return gemDB;
	}
	
	public ItemDB() {
		
		Set<Integer> items = new HashSet<Integer>();
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=430;maxle=483;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=484;maxle=500;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=501;maxle=510;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=511;maxle=530;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=531;maxle=550;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=4;minle=551;maxle=580;ub=4;cr=21;crs=1;crv=0"));
		
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=3;minle=430;maxle=500;ub=4;cr=21;crs=1;crv=0"));
		items.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items?filter=qu=3;minle=501;maxle=550;ub=4;cr=21;crs=1;crv=0"));
		
		System.out.println("Importing " + items.size() + " items");
		
		for(Integer id : items){
			System.out.print(id + ",");
		}
		
		for(Integer id : items){
			Item item = ItemDB.get(id,0,0);
			itemDB.add(item);
		}
		
		// trinkets mop
		
		// 5.4
		Set<Integer> trinkets54 = new HashSet<Integer>();
		trinkets54.addAll(Arrays.asList(105029, 104780, 102301, 105278, 104531, 105527 )); // haromms_talisman
		trinkets54.addAll(Arrays.asList(105082, 104833, 102302, 105331, 104584, 105580 )); // sigil_of_rampage    
		trinkets54.addAll(Arrays.asList(104974, 104725, 102292, 105223, 104476, 105472 )); // assurance_of_consequence
		trinkets54.addAll(Arrays.asList(105114, 104865, 102311, 105363, 104616, 105612 )); // ticking_ebon_detonator
		trinkets54.addAll(Arrays.asList(103686, 103986 )); // discipline of xuen timeless isle trinkets
		for(Integer id : trinkets54){
			Item item = ItemDB.get(id,0,0);
			itemDB.add(item);
		}
		
		Set<Integer> gems = new HashSet<Integer>();
		gems.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items=3?filter=qu=2:3;minle=86;maxle=90;eb=1"));
		gems.addAll(getIdsFromWowhead("http://"+wowheadPrefix+".wowhead.com/items=3?filter=qu=2:3:4;minle=86;maxle=90;cr=99;crs=11;crv=0"));
		
		gems.add(89873); // legendary weapon gem
		gems.add(95346); // legendary meta gem
		
		for(Integer id : gems){
			Gem gem = ItemDB.getGem(id);
			gemDB.add(gem);
		}
	}
	
	private static Item getItemFromWOWHEAD(int itemid){
		Item item = new Item();
		
		JSONObject data = getItemDataWowHead(itemid);
		JSONObject extra;
		try {
			extra = data.getJSONObject("extra");
			
			if(extra.has("id"))
				item.setId(extra.getInt("id"));
			item.setName(data.getString("name"));
			item.setIcon(data.getString("icon"));
			String tooltip = data.getString("tooltip");
			item.setTooltip(tooltip);
			item.setQuality(data.getInt("quality"));
			item.setUpgradable(true);
			
			if(extra.has("namedesc"))
				item.setTag(extra.getString("namedesc"));
			else
				item.setTag("");
				
			item.add(new StatBlock(data));
			
			if(data.has("dps"))
				item.setDps(data.getDouble("dps"));
			if(data.has("mledmgmax"))
				item.setMaxDmg(data.getInt("mledmgmax"));
			if(data.has("mledmgmin"))
				item.setMinDmg(data.getInt("mledmgmin"));
			if(data.has("speed"))
				item.setSpeed(data.getDouble("speed"));
			if(extra.has("classs"))
				item.setItemClass(extra.getInt("classs"));
			if(extra.has("level"))
				item.setItemLevel(extra.getInt("level"));
			if(extra.has("subclass")){
				item.setItemSubClass(extra.getInt("subclass"));
				if(data.has("dps")){
					//item.setWeaponType();
				}
			}
			if(extra.has("slot")){
				//item.setInventoryType(extra.getInt("slot"));
				item.setInventorySlot(extra.getInt("slot"));
			}
			
			// socket colors and socketbonus
			if(data.has("nsockets"))
				item.setNumSockets(data.getInt("nsockets"));
			if(data.has("socket1"))
				item.setSocket(0, data.getInt("socket1"));
			if(data.has("socket2"))
				item.setSocket(1, data.getInt("socket2"));
			if(data.has("socket3"))
				item.setSocket(2, data.getInt("socket3"));
//			if(data.has("socketbonus")){
//				DBCReader dbcReader = DBCReader.getInstance();
//				item.setSocketBonus(dbcReader.getSocketBonus(data.getInt("socketbonus")));
//				if(item.getSocketBonus() == null){
//					System.out.println(data.getString("name") + " " + data.getInt("socketbonus"));
//				}
//			}
//			if(extra.has("reqclass"))
//				item.setReqClass(extra.getInt("reqclass"));
//			if(data.has("reqskill"))
//				item.setReqSkill(data.getInt("reqskill"));
//			if(data.has("itemset"))
//				item.setSet(itemSetDB.getItemSetByItemId(itemid));
//			String gb = gearBuffDB.getGearBuff(itemid);
//			if(gb != null){
//				item.setGearBuff(gb);
//			}
		} catch (JSONException e) {
			e.printStackTrace();
		} catch (NullPointerException e) {
			e.printStackTrace();
			//return null;
		}
		
		return item;
	}
	
	private static JSONObject getItemDataWowHead(int item_id){
		
		JSONObject stats = null;
		String json = "";
		
		File file = new File("./wowhead/"+item_id+".xml");
		if(!file.exists()){
			json = loadURL("http://"+wowheadPrefix +".wowhead.com/item=" + item_id + "&xml");
		
			try {
				PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
				out.write(json);
				out.flush();
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}else{
			BufferedReader in;
			try {
				in = (new BufferedReader(new FileReader(file)));
				json = in.readLine();
				in.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		//System.out.println(json);
		try {
	        DocumentBuilderFactory dbf =
	            DocumentBuilderFactory.newInstance();
	        DocumentBuilder db = dbf.newDocumentBuilder();
	        InputSource is = new InputSource();
	        is.setCharacterStream(new StringReader(json));

	        Document doc = db.parse(is);
	        NodeList nodes = doc.getElementsByTagName("jsonEquip");
	        NodeList nodes2 = doc.getElementsByTagName("json");
	        
	        NodeList nodes3 = doc.getElementsByTagName("name");
	        NodeList nodes4 = doc.getElementsByTagName("icon");
	        
	        NodeList nodes5 = doc.getElementsByTagName("htmlTooltip");
	        
	        NodeList nodes6 = doc.getElementsByTagName("quality");

	        Element element = (Element) nodes.item(0);
	        if(element != null){
		        stats = new JSONObject("{" + element.getTextContent()+ "}");
		        Element element2 = (Element) nodes2.item(0);
		        JSONObject stats2 = new JSONObject("{" + element2.getTextContent()+ "}");
		        stats.put("extra", stats2);
	           
		        Element element3 = (Element) nodes3.item(0);
		        String stats3 = element3.getTextContent();
		        stats.put("name", stats3);
		        
		        Element element4 = (Element) nodes4.item(0);
		        String stats4 = element4.getTextContent();
		        stats.put("icon", stats4);
		        
		        Element element5 = (Element) nodes5.item(0);
		        String stats5 = element5.getTextContent();
		        stats.put("tooltip", stats5);
		        
		        Element element6 = (Element) nodes6.item(0);
		        String stats6 = element6.getAttribute("id");
		        stats.put("quality", stats6);
	        }
	    }
	    catch (Exception e) {
	    	System.out.println(item_id);
	        e.printStackTrace();
	    }
	    return stats;
	}
	
	private static String loadURL(String url) {
		InputStream is = null;
		BufferedReader rd = null;
		try {
			is = new URL(url).openStream();
			rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("not found: " + url);
			//e.printStackTrace();
			return "{\"status\":\"nok\", \"reason\": \"unable to get item information.\"}";
		}
		String cp = "";
		StringBuilder sb = new StringBuilder();
		try {
			while ((cp = rd.readLine()) != null) {
			      sb.append(cp);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			is.close();
			rd.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}
	
	private Set<Integer> getIdsFromWowhead(String url1){
		String url = loadURL(url1);
		Pattern pattern = Pattern.compile("\\_\\[(\\d*)\\]=\\{.*?\\}");
		Matcher matcher = pattern.matcher(url);
		Set<Integer> ret = new HashSet<Integer>();
		while (matcher.find()) {
			String s = matcher.group(1);
			int i = Integer.parseInt(s);
			ret.add(i);
		}
		return ret;
	}
}
